#include <iostream>
#include <cassert>
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"

using namespace std;

static int number = 1; // 编号
int num = 5; // 父进程管理进程数

class channel
{
public:
    channel(int fd, pid_t id)
        :ctrlfd(fd)
        ,workerid(id)
    {
        name = "channel-" + to_string(number++);
    }
public:
    int ctrlfd;
    pid_t workerid;
    std::string name;
};

void Work()
{
    while(true)
    {
        int code = 0;

        ssize_t n = read(0, &code, sizeof(code));
        if(n == sizeof(code))
        {
            if(!init.CheckSafe(code))
                continue;
            init.RunTask(code);
        }
        else if(n == 0)
        {
            break;
        }
        else
        {
            //Todo;
        }
    }
    cout << "child quit" << endl;
}

void PrintFd(const vector<int> &fds)
{
    for(auto &fd : fds)
    {
        cout << fd << " ";
    }
    cout << endl;
}

void CreateChannels(vector<channel> *c)
{
    vector<int> old;
    for(int i = 0; i < num; i++)
    {
        int pipefd[2];
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        // 创建进程
        pid_t id = fork();
        assert(id != -1);

        if(id == 0)
        {
            // 子进程
            if(!old.empty())
            {
                for(auto &fd : old)
                {
                    close(fd);
                }
                sleep(2);
                PrintFd(old);
            }
            close(pipefd[1]);
            // 传参时都是从标准输入中拿，而跳过传参
            dup2(pipefd[0], 0);
            Work();
            exit(0);
        }

        // 父进程
        close(pipefd[0]);
        c->push_back(channel(pipefd[1], id));
        old.push_back(pipefd[1]);
    }

}
void SendCommand(const vector<channel> &c, bool flag, int num)
{
    int pos = 0;
    while(true)
    {
        // 选择任务
        int command = init.SelectTask();
        // 选择信道
        const auto &channel = c[pos++];
        pos %= c.size();

        cout << "send command " << init.ToDesc(command) << "[" << command << "]"
        << " in "
        << channel.name << " worker is " << channel.workerid << endl; 

        // 发送任务
        write(channel.ctrlfd, &command, sizeof(command));

        // 判断是否退出
        if(!flag)
        {
            num--;
            if(num <= 0) break;
        }
        sleep(1);
    }

    cout << "SendCommand done..." << endl;
}

void ReleaseChannels(vector<channel> &c)
{

    // version 2
    // int num = c.size()-1;
    // for(; num >= 0; num--)
    // {
    //     close(c[num].ctrlfd);
    //     waitpid(c[num].workerid, nullptr, 0);
    // }

    // version 1
    for(auto &channel : c)
    {
        close(channel.ctrlfd);
        waitpid(c[num].workerid, nullptr, 0);
    }
    // for(auto &channel : c)
    // {
    //     pid_t rid = waitpid(channel.workerid, nullptr, 0);
    //     if(rid == channel.workerid)
    //     {
    //         cout << "wait " << channel.workerid << "success" << endl;
    //     }
    // }
}

// 传参形式：
// 1. 输入参数：const &
// 2. 输出参数：*
// 3. 输入输出参数：&

int main()
{
    // 先描述，再组织
    std::vector<channel> channels;
    // 1. 创建信道，创建进程
    CreateChannels(&channels);

    // 2. 开始发送任务
    const bool g_always_loop = true;

    // SendCommand(channels, g_always_loop);
    SendCommand(channels, !g_always_loop, 10);

    // 3. 回收资源，想让子进程退出，并且释放管道，只要关闭写端
    ReleaseChannels(channels);

    return 0;
}